#include <iostream>
#include <string>
#include <string_view>
#include <thread>
#include <sstream>

#include <Windows.h>

using namespace std;

CRITICAL_SECTION cs; // critical section (临界区)
int dwTickys = 50;   // tickys (剩余票数)

std::string GetTid();
void stringViewTest();
void doSales(int num);
int __stdcall saleTickys();
void runCriticalSectionTest1();

int main(int argc, char const *argv[])
{
    runCriticalSectionTest1();
    return 0;
}

std::string GetTid()
{
    std::ostringstream oss;
    oss << std::this_thread::get_id();
    return oss.str();
}

void stringViewTest()
{
    cout << "Hello String_View \n";

    /**
     * @brief string_view 只是字符串的观察者，对传入的字符串只读，不会破坏传入字符串
     */

    const char *cstr = "hello string view";
    std::string_view stringView1(cstr);
    std::string_view stringView2(cstr, 5);
    std::cout << "stringView1: " << stringView1 << ", stringView2: " << stringView2 << std::endl;
    // stringView1: hello string view, stringView2: hello

    std::string str(cstr);
    std::string_view stringView3(str.c_str());
    std::string_view stringView4(str.c_str(), 5);
    std::cout << "stringView3: " << stringView3 << ", stringView4: " << stringView4 << std::endl;
    // stringView3: hello string view, stringView4: hello

    str = "livio test";
    std::cout << "stringView3: " << stringView3 << ", stringView4: " << stringView4 << std::endl;
    // stringView3: livio testg view, stringView4: livio

    char buf[32] = {'0'};
    stringView3.copy(buf, str.size(), 0);
    std::cout << "buf: " << buf << ", stringView3: " << stringView3 << std::endl;

    stringView3.copy(buf, stringView3.size(), 0);
    std::cout << "buf: " << buf << ", stringView3: " << stringView3 << std::endl;

    stringView3.copy(buf, 32, 0);
    std::cout << "buf: " << buf << ", stringView3: " << stringView3 << std::endl;

    std::string_view svPath(str);
    if (svPath.starts_with("livio"))
        str = svPath.substr(6);

    cout << "str:" << str << ", svPath:" << svPath << std::endl;
}

void doSales(int num)
{
    // 每次出售num张票
    EnterCriticalSection(&cs);
    if (dwTickys > 0)
    {
        printf("当前的票数:%lu, 线程id:%s \n", dwTickys, GetTid().c_str());
        dwTickys -= num;
        printf("购票后票数:%lu, 线程id:%s \n", dwTickys, GetTid().c_str());
    }
    LeaveCriticalSection(&cs);
}

int __stdcall saleTickys()
{
    // 进行售票，只要还有剩余，就一直售卖
    while (dwTickys > 0)
    {
        doSales(1);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    return 0;
}

void runCriticalSectionTest1()
{
    /**
     * @brief 模拟售票流程，总计有m张票需要售卖。开n个柜台售卖，每个柜台单次出售k张，直到售完所有
     */
    InitializeCriticalSection(&cs);

    // 柜台1
    std::thread t1([]() -> int
                   {
                       std::ostringstream oss;
                       oss << "线程1开始，线程id:" << std::this_thread::get_id();
                       std::cout << oss.str() << std::endl;
        return saleTickys(); });

    // 柜台2
    std::thread t2([]() -> int
                   {
                       std::ostringstream oss;
                       oss << "线程2开始，线程id:" << std::this_thread::get_id();
                       std::cout << oss.str() << std::endl;
        return saleTickys(); });

    // 柜台3
    std::thread t3([]() -> int
                   {
                       std::ostringstream oss;
                       oss << "线程3开始，线程id:" << std::this_thread::get_id();
                       std::cout << oss.str() << std::endl;
        return saleTickys(); });

    t1.join();
    t2.join();
    t3.join();
}
